在開發過程中,我們時常會遇到這樣一種情況:當 Vue 的 data 裡面的宣告或者已經賦值過的對像或者陣列(陣列裡面的值是對象)時,向對像中添加新的屬性,如果更新此屬性的值,是不會更新視圖的。
根據官方文檔定義:如果在實例創建之後添加新的屬性到實例上,它不會觸發視圖更新。
受現代 JavaScript 的限制(以及廢棄 Object.observe),Vue 不能檢測到對象屬性的添加或刪除。由於 Vue 會在初始化實例時對屬性執行 getter
/setter
轉化過程,所以屬性必須在 data 對像上存在才能讓 Vue 轉換它,這樣才能讓它是響應的。
範例:
<div id="app">
<table class="table">
<tbody>
<tr is="row-component"
v-for="(item, key) in data"
:item="item"
:key="key">
</tr>
</tbody>
</table>
</div>
<script type="text/x-template" id="row-component">
<tr>
<td>{{ item.name }}</td>
<td>{{ item.cash }}</td>
<td>{{ item.icash }}</td>
<td>
<span v-if="data.item">{{ data.item.name }}</span>
<button class="btn btn-sm btn-primary" @click="addData()">寫入資料</button>
</td>
</tr>
</script>
var child = {
props: ['item'],
template: '#row-component',
data: function() {
return {
data: {}
}
},
methods: {
addData: function() {
this.data.item = {
name: this.item.name
}
console.log(this.data, this);
}
},
mounted: function() {
console.log('Component:', this)
}
}
var app = new Vue({
el: '#app',
data: {
data: [{
name: '小明',
cash: 100,
icash: 500,
}, {
name: '杰倫',
cash: 10000,
icash: 5000,
}, {
name: '漂亮阿姨',
cash: 500,
icash: 500,
}, {
name: '老媽',
cash: 10000,
icash: 100,
}, ]
},
components: {
"row-component": child
},
mounted: function() {
console.log('Vue init:', this)
}
});
我們先打開 console 看看 this 裡面是什麼東西:
這邊先看 Vue init 裡面,裡面有個 data ,我們打開之後會看到 (...) 的字樣:
會有這個結果是因為是使用 getter
、setter
的綁定,然後監控這個數據,所以當數據有更動的時候才會及時的顯示到畫面上,那麼也就是說如果你在寫入之料的時候,你發現沒有 getter
、setter
就代表說你的資料結構並沒有進入 vue 的綁定裡面。
接下來來看一下 component 的部分,我們如果在寫入資料的時候並沒有預先定義 data 裡面的資料結構的話會出錯,出錯的話就不會出現 getter
、setter
:
var child = {
props: ['item'],
template: '#row-component',
data: function() {
return {
data: {}
}
},
methods: {
addData: function() {
this.data.item = {
name: this.item.name
}
console.log(this.data, this);
}
},
mounted: function() {
console.log('Component:', this)
}
}
這邊我們就來做測試,當我們按下按鈕的時候 addData()
看看會發生什麼事情:
可以看到畫面上並沒有顯示出來人名,而且往 console 看 this
結構明明確實是有把資料寫入到 data 中,,也無法使用 vue 的其他語法,是因為它並沒有確實的寫進去。
把 addData
改寫成以下:
addData: function() {
this.$set(this.data, 'item', {
name: this.item.name
});
console.log(this.data, this);
}
}
這邊就是介紹到我們在寫 vue 的時候並沒有辦法預先的把資料結構訂得非常完整,尤其是像 Ajax 我們所找回來的資料沒辦法預先定義,那這個時候就可以使用 set
寫到 vue 的資料結構內。
Mixins 是一種讓元件共用功能的方法,它和 extend
有一點點像,但差別就是在於 extend
是由單一元件來作延伸,而 Minxins 可以混合多個元件的行為。使用方式即是將共用功能以物件(以下稱為 mixin object)的方式傳入 mixins option。mixin object 可傳入元件的任何 option,例如:data、computed 或 methods。當元件選用 Mixins 時,使用的 mixin object 會和此元件的其他 option 混用。
範例:
<div id="app">
<table class="table">
<tbody>
<tr is="row-component" v-for="(item, key) in data" :item="item" :key="key"></tr>
</tbody>
</table>
</div>
<script type="text/x-template" id="row-component">
<tr>
<td>{{ item.name }}</td>
<td>{{ item.cash | currency | dollarSign }}</td>
<td>{{ item.icash | currency | dollarSign }}</td>
</tr>
</script>
Vue.component('row-component', {
props: ['item'],
data: function() {
return {
data: {},
}
},
template: '#row-component',
filters: {
dollarSign: function(n) {
return `$ ${n}`
},
currency: function(n) {
return n.toFixed(2).replace(/./g, function(c, i, a) {
return i && c !== "." && ((a.length - i) % 3 === 0) ? ',' + c : c;
});
}
},
mounted() {
console.log('這段是 Mixin 產生')
}
});
var app = new Vue({
el: '#app',
data: {
data: [{
name: '小明',
cash: 100,
icash: 500,
}, {
name: '杰倫',
cash: 10000,
icash: 5000,
}, {
name: '漂亮阿姨',
cash: 500,
icash: 500,
}, {
name: '老媽',
cash: 10000,
icash: 100,
}, ]
},
mounted: function() {
console.log('Vue init:', this)
}
});
這邊我們嘗試使用 mixins
來把元件建起來:
var mixin = {
template: '#row-component',
filters: {
dollarSign: function(n) {
return `$ ${n}`
},
currency: function(n) {
return n.toFixed(2).replace(/./g, function(c, i, a) {
return i && c !== "." && ((a.length - i) % 3 === 0) ? ',' + c : c;
});
}
},
}
var mixinHook = {
mounted() {
console.log('這段是 Mixin 產生')
}
}
然後加入到元件中, mixins
吃的是陣列,所以可以有多個 mixin object:
Vue.component('row-component', {
props: ['item'],
data: function() {
return {
data: {},
}
},
template: '#row-component',
mixins: [mixin, mixinHook]
});
出來的畫面會跟先前一樣,額外的 hook 也能成功啟用。
當元件與使用的 mixin object 有相同的 option 時,如果是鉤子(hooks),就會全部被合併為一個陣列,因此皆能被執行,並且 mixin 物件中的鉤子會先被執行。
var mixin = {
created: function () {
console.log('mixin hook called');
}
};
new Vue({
mixins: [mixin],
created: function () {
console.log('component hook called');
}
});
Vue-给对象新增属性(使用Vue.$set())
Vue.js: Mixins